前言
关于setState的异步,随便一搜就是一堆文章,从各种现象到海量源码,长篇巨制洋洋洒洒,像我这样的新手看得云里雾里,晕头转向。但这个问题又无比简单,仅需理解两点浅显的道理,便能拨云见日:1.同步代码不可能异步;2.如果"异步"了,一定是执行顺序发生了改变。
1. 生命周期函数中
componentDidMount: 该方法执行完毕后才更新,state在更新时(render)再设置为新的值。setState后续的代码在生命周期函数中执行,此时state还未变更,因此表现出"异步"特性。
2.合成事件中
同理,setState在事件中同步执行完毕,react准备更新(will),state在更新时(render)再设置为新的值。setState后续的代码在触发事件时执行,顺序在state变更之前。
注:state的合并,只能将同步的setState合并掉,两次事件的变更无法合并,任你点击得再快
3.异步方法及原生事件
react监控的只有生命周期函数和合成事件,而非setState,在这两个方法执行前会先设置isBatchingUpdates为true,导致state等更新完毕后再改变,因此其他情况下,batchedUpdates为false,setState同步更新。同样,state也是在更新时设为新的值,但是setState后续的代码也是在更新完成之后执行,因此表现出同步特性。
注:同理,Promise的构造函数内的setState,因为构造函数的同步性,当其处于1和2的情况下时,也会呈现出"异步"
4.结论
- setState不是变更state的方法,只是发送了变更的请求
- 无论是生命周期函数还是合成事件函数,它们都会被放入react的事务中,而事务的前置钩子内会修改isBatchingUpdates为true
- 因isBatchingUpdates为true,setState会走批量更新模式,合并同样的state,并不即时修改state,从而使后续的同步代码在state变更前就执行了,表现出"异步"的特性
- react没有监控异步方法和原生事件,因此,即使它们声明的时候处在生命周期函数或者合成事件中,它们执行的时候,isBatchingUpdates必定已经被事务的后置钩子设为false了,因此表现出同步的特性
- 同步时,state的改变和后续代码的执行,都是在did update后,"异步"时,先即使执行了后续的代码,而后在did update之后执行了state的变更
- 最后的总结就是,setState是同步的,或者是带引号的"异步"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。